﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace PortableVersion.Core.FileSystem
{
    public class FileVersioningSource : IVersioningSource<FileItem>, IFolderBrowserService, IPopulatable<FileItem>
    {
        private readonly IFsoService _fso;
        private readonly IConfigurationProvider _config;
        private readonly List<FileItem> _items;
        private HashSet<string> _supportedTypes;
        private readonly FilePosition _position;

        public IEnumerable<FileItem> Items
        {
            get { return _items; }
        }

        public string Path { get; private set; }

        public string Id { get; private set; }

        public FileVersioningSource(string path, IFsoService fso, IConfigurationProvider config, FilePosition position)
        {
            _fso = fso;
            _config = config;
            Id = path;
            Path = path;
            _items = new List<FileItem>();
            _position = position;
        }

        /// <summary>
        /// Populates the versionig source from a folder
        /// </summary>
        private void Populate()
        {
            var dir = _fso.GetDirectoryInfo(Path);
            if (!dir.Exists)
            {
                throw new InvalidOperationException(
                    String.Format("Can not populate from directory {0} because it does not exist", Path));
            }
            _supportedTypes =
                new HashSet<string>(FileSystemHelper.GetSupportedTypes(_config.GetValue<string>("supportedTypes")));
            var files = dir.GetFiles("*.*", SearchOption.AllDirectories);
            var itemList = files.Where(fileInfo => _supportedTypes.Contains(fileInfo.Extension)).Select(fileInfo => new FileItem
                                                                                                                        {
                                                                                                                            CreatedDate = fileInfo.CreationTimeUtc, ModifiedDate = fileInfo.LastWriteTimeUtc, Path = fileInfo.FullName, Position = _position, IsFolder = false
                                                                                                                        }).ToList();
            var allDirs = itemList.Select(i => System.IO.Path.GetDirectoryName(i.Path)).Distinct().ToLookup(i => i);
            var folders = dir.GetDirectories("*.*", SearchOption.AllDirectories);
            //only add directories that have selected files
            itemList.AddRange(folders.Where(fileInfo => allDirs.Contains(fileInfo.FullName)).Select(fileInfo => new FileItem
                                                                                                                    {
                                                                                                                        CreatedDate = fileInfo.CreationTimeUtc, ModifiedDate = fileInfo.LastWriteTimeUtc, Path = fileInfo.FullName, Position = _position, IsFolder = true
                                                                                                                    }));
            _items.AddRange(itemList.OrderBy(i => i.Path));
        }

        /// <summary>
        /// Populates itself. For simplicity we merged the serive and source.
        /// </summary>
        void IFolderBrowserService.Populate<T>(IVersioningSource<T> versioningSource)
        {
            if (versioningSource!=null && !versioningSource.Equals(this))
            {
                throw new InvalidOperationException("FileVersioningSource can only populate itself.");
            }
            Populate();
        }

        public void AddItem(FileItem item)
        {
            _items.Add(item);
        }

        public void AddItemRange(IEnumerable<FileItem> itemRange)
        {
            _items.AddRange(itemRange);
        }
    }
}
